using System;
using System.Collections;
using UnityEngine;
using System.Collections.Generic;
using Battle;

public struct Node
{

	int idx;

	public Node (int index)
	{
  
		this.idx = index;
	}

	public void Set (int index)
	{

		this.idx = index;
	}

	public static implicit operator int (Node n)
	{
		return n.idx;
	}

	public static implicit operator Node (int i)
	{
		return new Node (i);
	}
}

public class MapInput
{
	public int width;
	public int height;
	public float gridLength;
	public Vector3 original;
	public List<int> Roads = new List<int> ();
	public List<int> River = new List<int> ();

	public MapInput ()
	{
		width = 50;
		height = 50;
		gridLength = 1;
		
		for (int i=0; i<width*height; ++i) {
			if (X (i) >= 5 && X (i) <= 10
			    && Y (i) >= 5 && Y (i) <= 45) {
				Roads.Add (i);
				continue;
			}
			if (X (i) >= 40 && X (i) <= 45
			    && Y (i) >= 5 && Y (i) <= 45) {
				Roads.Add (i);
				continue;
			}
			
			if (Y (i) >= 20 && Y (i) <= 30) {
				River.Add (i);
				continue;
			}
		}
	}

	public int X (int index)
	{
		return index % width;
	}
	
	public int Y (int index)
	{
		return index / width;
	}
}

public interface  IMap
{
	void Init (MapInput input);

	Vector3 Position (int index);

	int     Index (Vector3 pos);

	bool    InMap (int index);

	int     Count ();
}

public class Map : IMap
{
	protected int width;
	protected int height;
	protected float gridLength;
	Node[] nodes;
	Vector3 minPos;
	Vector3 maxPos;
	Vector3 original;

	public virtual void Init (MapInput input)
	{
		this.width = input.width;
		this.height = input.height;
		this.gridLength = input.gridLength;
		nodes = new Node[width * height];
		for (int i = 0; i < nodes.Length; ++i) {
			nodes [i].Set (i);
		}
		this.original = input.original;
		this.minPos = new Vector3 (original.x, original.y);
		this.maxPos = minPos + new Vector3 (gridLength * width, gridLength * height);
	}

	public float GridLength ()
	{
		return gridLength;
	}

	public int Count ()
	{
		return nodes.Length;
	}

	public Vector3 Position (int index)
	{
		Vector3 offset = new Vector3 (X (index), Y (index), 0) * gridLength;
		return offset + original;
	}

	public int Index (Vector3 pos)
	{
		Vector3 offset = pos - original;
		int x = (int)(offset.x / gridLength);
		int y = (int)(offset.y / gridLength);
		return Index (x, y);
	}

	public int Index (int x, int y)
	{
		return x + y * width;
	}

	public int X (int index)
	{
		return index % width;
	}

	public int Y (int index)
	{
		return index / width;
	}

	public bool InMap (int index)
	{
		return 0 <= index && index < Count ();
	}

	public bool InMap (Vector3 position)
	{
		return position.x >= minPos.x && position.y >= minPos.y
			&& position.x <= maxPos.x && position.y <= maxPos.y;
	}

	public const int MaxNeighboursCount = 4;

	public int Neighbours (int index, ref Node[] neighbours)
	{
		int count = 0;
		if (InMap (index - 1) && !LeftColumn (index)) {
			neighbours [count++] = nodes [index - 1];
		}
		if (InMap (index + width)) {
			neighbours [count++] = nodes [index + width];
		}
		if (InMap (index + 1) && !RightColumn (index)) {
			neighbours [count++] = nodes [index + 1];
		}
		if (InMap (index - width)) {
			neighbours [count++] = nodes [index - width];
		}
		return count;
	}

	public const int MaxAroundsCount = 9;

	public int Arounds (int index, ref Node[] arounds)
	{
		int count = 0;
		//left
		if (InMap (index - 1) && !LeftColumn (index)) {
			arounds [count++] = nodes [index - 1];
		}
		//top left
		if (InMap (index - 1 + width) && !LeftColumn (index)) {
			arounds [count++] = nodes [index - 1 + width];
		}
		//top
		if (InMap (index + width)) {
			arounds [count++] = nodes [index + width];
		}
		//top right
		if (InMap (index + width + 1) && !RightColumn (index)) {
			arounds [count++] = nodes [index + width + 1];
		}
		//right
		if (InMap (index + 1) && !RightColumn (index)) {
			arounds [count++] = nodes [index + 1];
		}
		//bottom right
		if (InMap (index + 1 - width) && RightColumn (index)) {
			arounds [count++] = nodes [index + 1 - width];
		}
		//bottom
		if (InMap (index - width)) {
			arounds [count++] = nodes [index - width];
		}
		//bottom left
		if (InMap (index - 1 - width) && !LeftColumn (index)) {
			arounds [count++] = nodes [index - 1 - width];
		}
		return count;
	}

	public bool LeftColumn (int index)
	{
		return index % width == 0;
	}

	public bool RightColumn (int index)
	{
		return index % width == (width - 1);
	}

	public bool TopRow (int index)
	{
		return index / width == (height - 1);
	}

	public bool BottomRow (int index)
	{
		return index / width == 0;
	}

	public Vector3 FixedPosition (Vector3 pos)
	{
		pos.x = Mathf.Clamp (pos.x, minPos.x, maxPos.x - 0.0001f);
		pos.y = Mathf.Clamp (pos.y, minPos.y, maxPos.y - 0.0001f);
		return pos;
	}

	public int InRange (Vector3 pos, float range, ref Node[] neighbours)
	{
		int count = 0;
		Vector3 lbPos = FixedPosition (pos - new Vector3 (range, range));
		Vector3 tpPos = FixedPosition (pos + new Vector3 (range, range));
		int lbIndex = Index (lbPos);
		int tpIndex = Index (tpPos);
		int index = 0;
		for (int x=X(lbIndex); x<=X (tpIndex); ++x) {
			for (int y=Y(lbIndex); y<=Y(tpIndex); ++y) {
				index = Index (x, y);
				if (InMap (index)) {
					neighbours [count++] = nodes [Index (x, y)];
				}
			}
		}
		return count;
	}

	public virtual int Cost (Node current, Node next, Actor actor)
	{
		return 0;
	}

	public virtual int Heuristic (Node goal, Node next, Actor actor)
	{
		return 0;
	}
}

public enum TerrainType
{
	Plain,
	Road,
	River,
}

public class BattleNode
{
	public List<Actor> actors = new List<Actor> ();
	public TerrainType terrain = TerrainType.Plain;

	public bool Contain (Actor a)
	{
		for (int i=0; i<actors.Count; ++i) {
			if (actors [i] == a)
				return true;
		}
		return false;
	}
}

